home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / applets / plot2d / dataset.jav < prev    next >
Encoding:
Text File  |  1995-12-15  |  13.4 KB  |  511 lines

  1. import java.awt.*;
  2. import java.applet.*;
  3. import java.util.*;
  4. import java.lang.*;
  5.  
  6.  
  7. /*************************************************************************
  8. **
  9. **    Class  DataSet
  10. **                                              Version 1.0   October 1995
  11. **
  12. **************************************************************************
  13. **    Copyright (C) 1995 Leigh Brookshaw
  14. **
  15. **    This program is free software; you can redistribute it and/or modify
  16. **    it under the terms of the GNU General Public License as published by
  17. **    the Free Software Foundation; either version 2 of the License, or
  18. **    (at your option) any later version.
  19. **
  20. **    This program is distributed in the hope that it will be useful,
  21. **    but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. **    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. **    GNU General Public License for more details.
  24. **
  25. **    You should have received a copy of the GNU General Public License
  26. **    along with this program; if not, write to the Free Software
  27. **    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28. **************************************************************************
  29. **
  30. **    This class is designed to be used in conjunction with 
  31. **    the Graph2D class and Axis class for plotting 2D graphs.
  32. **
  33. *************************************************************************/
  34.  
  35.  
  36. /*
  37. **  Class DataSet
  38. **               This object is designed to hold the data to be plotted
  39. **               The data is stored in an array with the x,y data
  40. **               stored adjacently. The x data in even indices, y data in odd.
  41. **               Along with the data are a number of flags associated
  42. **               with the data defining how this data is to be plotted.
  43. */
  44.  
  45.  
  46. public class DataSet extends Object {
  47.  
  48.  
  49. /**************************
  50. ** Public Static Values     
  51. **************************/
  52. /*
  53. **    The static value specifying that no straight line segment
  54. **    is to join the points.
  55. */
  56.       public final static int NOLINE    =  0;
  57. /*
  58. **    The static value specifying that a straight line segment
  59. **    is to join the points.
  60. */
  61.       public final static int LINE      =  1;
  62.  
  63.  
  64.  
  65. /**********************
  66. ** Public Variables      
  67. **********************/
  68.  
  69. /* 
  70. ** g2d
  71. **    The Graphics canvas that is driving the whole show
  72. **    See class Graph2D
  73. */
  74.       public Graph2D g2d;
  75.  
  76. /*
  77. ** linestyle
  78. **    The linestyle to employ when joining the data points with
  79. **    straight line segments. Currently only solid and no line
  80. **    are supported. Dashed lines will be added
  81. */
  82.       public int   linestyle     = LINE;
  83. /*
  84. ** linecolor
  85. **    The color of the straight line segments
  86. */
  87.       public Color linecolor     = null;
  88. /*
  89. ** marker
  90. **    The index of the marker to use at the data points
  91. **    markers are stroked.
  92. */
  93.       public int    marker       = 0;
  94. /*
  95. ** markercolor
  96. **    The marker color
  97. */
  98.       public Color  markercolor  = null;
  99. /*
  100. ** markerscale
  101. **    The scaling factor for the marker
  102. */
  103.       public double markerscale  = 1.0;
  104. /*
  105. ** xaxis
  106. **    The Axis object the X data is attached to. From the Axis obeject
  107. **    the scaling for the data can be calculated.
  108. */
  109.       public Axis xaxis;
  110. /*
  111. ** yaxis
  112. **    The Axis object the Y data is attached to.
  113. */
  114.       public Axis yaxis;
  115. /*
  116. ** xmax, xmin, ymax, ymin
  117. **    The plottable range of the data. This can be very different from
  118. **    true data range. The data is clipped when plotted.
  119. */
  120.       public double xmax, xmin, ymax, ymin;
  121.  
  122. /*
  123. ** legend_length
  124. **    The length of the line in the legend
  125. */
  126.       int legend_length = 20;
  127. /*
  128. ** legend_color
  129. **    The color of the text in the legend
  130. */
  131.       Color legend_color;
  132. /*
  133. ** legend_text
  134. **    The legend text
  135. */
  136.       String legend_text;
  137. /*
  138. ** legend_font
  139. **    The font to use for the legend text
  140. */
  141.       Font legend_font;
  142. /*
  143. ** legend_x, legend_y
  144. **    
  145. */
  146.       int legend_x, legend_y;
  147.  
  148.  
  149. /**********************
  150. ** Protected Variables      
  151. **********************/
  152. /*
  153. ** dxmax, dxmin, dymax, dymin
  154. **    The true data range. Once the data is loaded this will never change.
  155. */
  156.       protected double dxmax, dxmin, dymax, dymin;
  157.  
  158. /*
  159. ** data[]
  160. **    The actual data
  161. */
  162.       protected double data[];
  163. /*
  164. ** xrange, yrange
  165. **    The range of the clipped data
  166. */
  167.       protected double xrange, yrange;
  168.  
  169.  
  170. /********************
  171. ** Constructors
  172. ********************/
  173.  
  174. /*
  175. ** DataSet(double[], int)
  176. **   The double array contains the data. The X data is expected in
  177. **   the even indices, the y data in the odd. The integer n is the
  178. **   number of data Points. This manes that the length of the data
  179. **   array is 2*n.
  180. */
  181.       public DataSet ( double d[], int n ) throws Exception {
  182.            int i;
  183.            int k = 0;
  184.  
  185.            if ( d  == null || d.length == 0 || n <= 0 ) {
  186.               throw new Exception("DataSet: Error in parsed data!");
  187.            }
  188.  
  189. //     Copy the data locally.
  190.  
  191.            data = new double[n*2];
  192.  
  193.            System.arraycopy(d, 0, data, 0, n*2);
  194.  
  195.  
  196. //     Calculate the data range.   
  197.  
  198.            dxmax = data[0];
  199.            dymax = data[1];
  200.            dxmin = dxmax;
  201.            dymin = dymax;
  202.  
  203.  
  204.            for(i=1; i<data.length-1; ) {
  205.  
  206.              i++;
  207.              if( dxmax < data[i] ) { dxmax = data[i]; }
  208.              else
  209.              if( dxmin > data[i] ) { dxmin = data[i]; }
  210.  
  211.              i++;
  212.              if( dymax < data[i] ) { dymax = data[i]; }
  213.              else
  214.              if( dymin > data[i] ) { dymin = data[i]; }
  215.            }
  216.  
  217.            xmin = dxmin;
  218.            xmax = dxmax;
  219.            ymin = dymin;
  220.            ymax = dymax;
  221.  
  222.       }
  223.  
  224.  
  225.  
  226. /******************
  227. ** Public Methods
  228. ******************/
  229.  
  230.  
  231. /*
  232. ** draw_data(Graphics)
  233. **    Actually draw the straight line segments and/or the markers at the
  234. **    data points.
  235. **
  236. **    If this data has been attached to an Axis then scale the data
  237. **    based on the axis maximum/minimum otherwise scale using
  238. **    the data's maximum/minimum
  239. **
  240. **    Use the clipRect of the graphics object to define the window we
  241. **    have to draw into.
  242. */
  243.  
  244.       public void draw_data(Graphics g) {
  245.            Color c;
  246.  
  247.            if ( xaxis != null ) {
  248.                 xmax = xaxis.maximum;
  249.                 xmin = xaxis.minimum;
  250.            }
  251.  
  252.            if ( yaxis != null ) {
  253.                 ymax = yaxis.maximum;
  254.                 ymin = yaxis.minimum;
  255.            }
  256.  
  257.            
  258.            xrange = xmax - xmin;
  259.            yrange = ymax - ymin;
  260.  
  261.            c = g.getColor();
  262.  
  263.            if( linestyle != DataSet.NOLINE ) {
  264.                if ( linecolor != null) g.setColor(linecolor);
  265.                else                    g.setColor(c);
  266.                draw_lines(g);
  267.            }    
  268.  
  269.  
  270.            if( marker > 0 ) {
  271.                if(markercolor != null) g.setColor(markercolor);
  272.                else                    g.setColor(c);
  273.                draw_markers(g);
  274.            }    
  275.  
  276.  
  277.  
  278.  
  279.  
  280.            g.setColor(c);
  281.       }
  282.  
  283.  
  284.       public double getXmax() {  return dxmax; } 
  285.       public double getXmin() {  return dxmin; } 
  286.       public double getYmax() {  return dymax; } 
  287.       public double getYmin() {  return dymin; }
  288.  
  289.  
  290.       public void dataLegend(int x, int y, String text) {
  291.            if(text == null) { legend_text = null;  return; }
  292.            legend_text = text;
  293.            legend_x    = x;
  294.            legend_y    = y;
  295.       }
  296.  
  297.  
  298. /******************
  299. ** Protected Methods
  300. ******************/
  301.  
  302. /*
  303. ** draw_lines(Graphics)
  304. **
  305. ** Actually draw into the clipRect the straight line segments
  306. ** At some future date this method will be extended to draw dashed lines.
  307. **
  308. ** To save time don't bother to try and draw segments that will be 
  309. ** completely clipped. Only Draw segments that are not clipped or partially
  310. ** clipped. 
  311. */
  312.  
  313.       protected void draw_lines(Graphics g) {
  314.           int i;
  315.           int j;
  316.           boolean inside0 = false;
  317.           boolean inside1 = false;
  318.           Rectangle w = g.getClipRect();
  319.           double x,y;
  320.           int x0 = 0 , y0 = 0;
  321.           int x1 = 0 , y1 = 0;
  322.  
  323.  
  324. //    Is the first point inside the clipping region ?
  325.           if( inside(data[0], data[1]) ) {
  326.  
  327.               x0 = (int)(w.x + ((data[0]-xmin)/xrange)*w.width);
  328.               y0 = (int)(w.y + (1.0 - (data[1]-ymin)/yrange)*w.height);
  329.  
  330.                     inside0 = true;
  331.           } else {
  332.                     inside0 = false;
  333.           }
  334.  
  335.  
  336.           for(i=2; i<data.length; i+=2) {
  337.  
  338. //        Is this point inside the clipping region?
  339.               if( inside( data[i], data[i+1]) ) {
  340.                     inside1 = true;
  341.               } else {
  342.                     inside1 = false;
  343.               }
  344.              
  345. //        If one point is inside the clipping region calculate the second point
  346.               if ( inside1 || inside0 ) {
  347.  
  348.                x1 = (int)(w.x + ((data[i]-xmin)/xrange)*w.width);
  349.                y1 = (int)(w.y + (1.0 - (data[i+1]-ymin)/yrange)*w.height);
  350.  
  351.               }
  352. //        If the second point is inside calculate the first point if it
  353. //        was outside
  354.               if ( !inside0 && inside1 ) {
  355.  
  356.                 x0 = (int)(w.x + ((data[i-2]-xmin)/xrange)*w.width);
  357.                 y0 = (int)(w.y + (1.0 - (data[i-1]-ymin)/yrange)*w.height);
  358.  
  359.               }
  360. //        If either point is inside draw the segment
  361.               if ( inside0 || inside1 )  {
  362.                       g.drawLine(x0,y0,x1,y1);
  363.               }
  364.  
  365. /*
  366. **        The reason for the convolution above is to avoid calculating
  367. **        the points over and over. Now just copy the second point to the
  368. **        first and grab the next point
  369. */
  370.               inside0 = inside1;
  371.               x0 = x1;
  372.               y0 = y1;
  373.  
  374.           }
  375.  
  376.       }
  377.  
  378.  
  379. /*
  380. ** boolean inside(double, double)
  381. **         
  382. **    return true if the point(x,y) is inside the alowed range.
  383. */
  384.  
  385.       protected boolean inside(double x, double y) {
  386.           if( x >= xmin && x <= xmax && 
  387.               y >= ymin && y <= ymax )  return true;
  388.           
  389.           return false;
  390.       }
  391.  
  392. /*
  393. **  draw_markers(Graphics)
  394. **
  395. **    Draw the markers. The markers have been preloaded from a file.
  396. **    (see the method Graph2D.loadMarker(URL)).
  397. **    Only markers inside the specified range will be drawn. Also markers
  398. **    close the edge of the clipping region will be clipped.
  399. **
  400. **    The markers are stroked based on the preloaded marker definitions.
  401. */
  402.       protected void draw_markers(Graphics g) {
  403.           int x1,y1;
  404.           int i;
  405.           Rectangle w = g.getClipRect();
  406. /*
  407. **        Load the marker specified for this data
  408. */
  409.           Vector m = g2d.getMarkerVector(marker);
  410.  
  411.  
  412.           if( m == null) return;
  413.  
  414.  
  415.           for(i=0; i<data.length; i+=2) {
  416.               if( inside( data[i], data[i+1]) ) {
  417.  
  418.                 x1 = (int)(w.x + ((data[i]-xmin)/xrange)*w.width);
  419.                 y1 = (int)(w.y + (1.0 - (data[i+1]-ymin)/yrange)*w.height);
  420.  
  421.                     stroke_marker(m, g, x1, y1);
  422.                 }
  423.           }
  424.  
  425.  
  426.       }
  427. /*
  428. ** stroke_marker(Vector, Graphics, int, int)
  429. **
  430. **         Stroke the marker centered at the point x,y.
  431. **   The vector contains the definition of the marker. Marker definitions
  432. **   are centered on (0,0) and specify move and draw commands for each
  433. **   point.
  434. */
  435.  
  436.  
  437.       protected void stroke_marker(Vector m, Graphics g, int x, int y) {
  438.           int x0 = x, x1 = x, y0 = y, y1 = y;
  439.           MVertex v;
  440.  
  441.           for (Enumeration e = m.elements() ; e.hasMoreElements() ;) {
  442.              v = (MVertex)e.nextElement();
  443.  
  444.              if( v.draw ) {
  445.                  x1 = x + (int)(v.x*markerscale);
  446.                  y1 = y + (int)(v.y*markerscale);
  447.  
  448.                  g.drawLine(x0,y0,x1,y1);
  449.  
  450.                  x0 = x1;
  451.                  y0 = y1;
  452.              } else {
  453.                  x0 = x + (int)(v.x*markerscale);
  454.                  y0 = y + (int)(v.y*markerscale);
  455.  
  456.              }
  457.  
  458.  
  459.  
  460.           }
  461.  
  462.      }
  463.  
  464. /*
  465. ** draw_legend( Graphics g )
  466. **             Draw a legend for this data set using the data colors and the
  467. **             supplied text
  468. */
  469.  
  470.       protected void draw_legend(Graphics g) {
  471.           Color c = g.getColor();
  472.           Font  f = g.getFont();
  473.           FontMetrics fm;
  474.           Vector m;
  475.  
  476.           if( legend_text == null ) return;
  477.  
  478.           if( linestyle != DataSet.NOLINE ) {
  479.               if ( linecolor != null) g.setColor(linecolor);
  480.               g.drawLine(legend_x,legend_y,legend_x+legend_length,legend_y);
  481.           }
  482.  
  483.           if( marker > 0 ) {
  484.                m = g2d.getMarkerVector(marker);
  485.                if( m != null) {
  486.                   if(markercolor != null) g.setColor(markercolor);
  487.                   else                    g.setColor(c);
  488.  
  489.                   stroke_marker(m, g, legend_x+legend_length/2, legend_y);
  490.                }
  491.           }
  492.  
  493.           if( legend_color != null)   g.setColor(legend_color);
  494.           else                        g.setColor(c);
  495.           if( legend_font != null)    g.setFont(legend_font);
  496.  
  497.           fm = g.getFontMetrics();
  498.           g.drawString( legend_text,
  499.                         legend_x+legend_length+fm.charWidth('x'),
  500.                         legend_y+fm.getAscent()/3);
  501.  
  502.           g.setColor(c);
  503.           g.setFont(f);
  504.  
  505.  
  506.       }
  507.  
  508. }
  509.  
  510.  
  511.